using Tycho.Parser.Tokens;

namespace Tycho.Parser.Peg {
    public class MultipleRule<Context> : Rule<Context> {
        private readonly int Maximum;
        private readonly int Minimum;
        private readonly Rule<Context> Rule;

        public MultipleRule (int minimum, int maximum, Rule<Context> rule) {
            Minimum = minimum;
            Maximum = maximum;
            Rule = rule;
        }

        protected override RuleParseResult<Context> ReallyParse (Token[] tokens, int index, Context context) {
            int matches = 0;
            RuleParseResult<Context> lastResult = Rule.Parse (tokens, index, context);

            if (lastResult != null) {
                matches++;

                while (LessThanMaximum (matches)) {
                    RuleParseResult<Context> speculativeResult = Rule.Parse (tokens, lastResult.Index, lastResult.Context);

                    if (speculativeResult == null) {
                        if (matches >= Minimum) {
                            return lastResult;
                        } else {
                            return null;
                        }
                    } else {
                        speculativeResult.MergeCapturesFrom (lastResult);
                        lastResult = speculativeResult;
                    }

                    matches++;
                }

                return lastResult;
            } else if (matches >= Minimum) {
                return new RuleParseResult<Context> (index, context);
            } else {
                return null;
            }
        }

        private bool LessThanMaximum (int matches) {
            if (Maximum == -1) {
                return true;
            } else {
                return matches < Maximum;
            }
        }
    }
}